// Copyright (C) 2025 Focus Media Holding Ltd. All Rights Reserved.

package cn.pacerx.running.wx.service;

import static com.github.pagehelper.page.PageMethod.startPage;

import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import javax.validation.constraints.NotNull;

import cn.pacerx.running.db.domain.RunningOrder;
import cn.pacerx.running.db.domain.UserActivity;
import cn.pacerx.running.db.enums.ActivityTypeEnum;
import cn.pacerx.running.db.enums.GroupTypeEnum;
import cn.pacerx.running.db.enums.UserActivityStatusEnum;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import cn.pacerx.running.core.util.ResponseUtil;
import cn.pacerx.running.core.viewobject.OrderClauseVo;
import cn.pacerx.running.db.dao.ActivityMapper;
import cn.pacerx.running.db.domain.Activity;
import cn.pacerx.running.db.enums.ActivityStatusEnum;
import cn.pacerx.running.wx.dto.ActivityDto;
import cn.pacerx.running.wx.dto.UserActivityDto;
import cn.pacerx.running.wx.util.UserUtil;
import cn.pacerx.running.wx.vo.ActivityPagedVo;
import cn.pacerx.running.wx.vo.ActivityVo;
import io.mybatis.mapper.example.Example;
import lombok.RequiredArgsConstructor;

/**
 * EventService
 *
 * @author zhanglingwei@focusmedia.cn
 * @since 2025-06-08
 */
@Service
@RequiredArgsConstructor
public class ActivityService {
    private final ActivityMapper activityMapper;
    private final UserActivityService userActivityService;

    public Object getPagedList(ActivityPagedVo request) {
        startPage(request.getPage(), request.getLimit());
        Example<Activity> example = new Example<>();
        Example.Criteria<Activity> criteria = example.createCriteria();
        // 构建查询条件
        criteria.andNotEqualTo(Activity::getStatus, ActivityStatusEnum.OBSOLETED);
        if (request.getType() != null && request.getType() != ActivityTypeEnum.ALL) {
            criteria.andEqualTo(Activity::getType, request.getType());
        }
        if (request.getGroupType() != null && request.getGroupType() != GroupTypeEnum.ALL) {
            criteria.andEqualTo(Activity::getGroupType, request.getGroupType());
        }
        // 排序条件
        List<OrderClauseVo> orderByClause = request.getOrderByClause();
        if (CollectionUtils.isNotEmpty(orderByClause)) {
            orderByClause.forEach(orderClause -> example.orderBy(" order by "
                    + orderClause.getCol() + (orderClause.isAsc() ? Example.Order.ASC : Example.Order.DESC)));
        }
        // 查询活动列表
        List<Activity> activityList = activityMapper.selectByExample(example);
        if (CollectionUtils.isNotEmpty(activityList)) {
            Set<Long> activityIds = activityList.stream().map(Activity::getId).collect(Collectors.toSet());
            // 查询用户参与的活动
            Map<Long, UserActivityStatusEnum> userActivityMap = userActivityService.getList(activityIds).stream()
                    .collect(Collectors.toMap(UserActivityDto::getActivityId, UserActivityDto::getStatus));

            List<ActivityVo> activityVos = activityList.stream()
                    .map(activity -> {
                        ActivityVo activityVo = toVo(activity);
                        activityVo.setJoinedStatus(userActivityMap.get(activity.getId()));
                        return activityVo;
                    })
                    .collect(Collectors.toList());
            return ResponseUtil.okList(activityVos, activityList);
        }
        return ResponseUtil.okList(Collections.emptyList());
    }

    public Object getMinePagedList(ActivityPagedVo request) {
        List<UserActivity> userActivityList = userActivityService.getMinePagedList(request);
        // 查询活动列表
        if (CollectionUtils.isNotEmpty(userActivityList)) {
            Map<Long, UserActivityStatusEnum> activityJoinStatusMap = userActivityList.stream()
                    .collect(Collectors.toMap(UserActivity::getActivityId, UserActivity::getStatus));

            List<ActivityDto> activityDtos = activityMapper.wrapper()
                    .in(Activity::getId, activityJoinStatusMap.keySet())
                    .stream()
                    .map(this::toDto)
                    .peek(x -> x.setJoinedStatus(activityJoinStatusMap.get(x.getId())))
                    .collect(Collectors.toList());
            return ResponseUtil.okList(activityDtos, userActivityList);
        }
        return ResponseUtil.okList(Collections.emptyList());
    }

    private Set<String> buildExtraTag(Activity activity) {
        Set<String> extraTag = new HashSet<>();
        if (activity.getGroupType() == GroupTypeEnum.INDIVIDUAL) {
            extraTag.add("个人");
        } else {
            extraTag.add("团队");
        }
        if (activity.getType() == ActivityTypeEnum.RUN) {
            extraTag.add("跑步");
        } else if (activity.getType() == ActivityTypeEnum.CYCLING) {
            extraTag.add("骑行");
        } else if (activity.getType() == ActivityTypeEnum.HIKING) {
            extraTag.add("徒步");
        } else if (activity.getType() == ActivityTypeEnum.SWIMMING) {
            extraTag.add("游泳");
        }
        return extraTag;
    }

    public Object getById(Long id) {
        return activityMapper.wrapper()
                .eq(Activity::getId, id)
                .one()
                .map(this::toDto)
                .map(activityDto -> {
                    // 查询用户是否参与的活动
                    List<UserActivityDto> historyList = userActivityService.getHistoryList(activityDto.getUserId(), 8);
                    if (CollectionUtils.isNotEmpty(historyList)) {
                        activityDto.setJoinedUsers(historyList);
                    }
                    UserActivityDto userActivityDto = userActivityService.getDetail(id);
                    if (Objects.nonNull(userActivityDto)) {
                        activityDto.setJoinedStatus(userActivityDto.getStatus());
                        activityDto.setRemark(userActivityDto.getRemark());
                    }
                    return activityDto;
                })
                .map(ResponseUtil::ok)
                .orElseGet(ResponseUtil::badArgumentValue);
    }

    private ActivityDto toDto(Activity activity) {
        ActivityDto activityDto = new ActivityDto();
        BeanUtils.copyProperties(activity, activityDto);
        if (CollectionUtils.isNotEmpty(activityDto.getTag())) {
            activityDto.getTag().addAll(buildExtraTag(activity));
        } else {
            activityDto.setTag(buildExtraTag(activity));
        }
        return activityDto;
    }

    private ActivityVo toVo(Activity activity) {
        ActivityVo activityVo = new ActivityVo();
        BeanUtils.copyProperties(activity, activityVo);
        if (CollectionUtils.isNotEmpty(activityVo.getTag())) {
            activityVo.getTag().addAll(buildExtraTag(activity));
        } else {
            activityVo.setTag(buildExtraTag(activity));
        }
        return activityVo;
    }

    public List<Activity> getList() {
        Long userId = UserUtil.getUserId();
        return activityMapper.wrapper()
                .eq(Activity::getUserId, userId)
                .list();
    }

    public Object save(ActivityDto activityDto) {
        Long userId = UserUtil.getUserId();
        if(userId == null || userId == 0) {
            return ResponseUtil.unlogin();
        }

        if (activityDto.getId() == null) {
            Activity activity = new Activity();
            BeanUtils.copyProperties(activityDto, activity);

            activity.setId(null);
            activity.setUserId(userId);
            activity.setStatus(ActivityStatusEnum.PENDING);
            activityMapper.insert(activity);
            return ResponseUtil.ok(activity.getId());
        }
        // 更新
        return activityMapper.wrapper()
                .eq(Activity::getId, activityDto.getId())
                .eq(Activity::getUserId, userId)
                .one()
                .map(activity -> {
                    // 已删除的不允许更新
                    if (activity.getStatus() == ActivityStatusEnum.OBSOLETED) {
                        return ResponseUtil.badArgumentValue();
                    }
                    activity.setTitle(activityDto.getTitle());
                    activity.setType(activityDto.getType());
                    activity.setCoverUrl(activityDto.getCoverUrl());
                    activity.setGroupType(activityDto.getGroupType());
                    activity.setTag(activityDto.getTag());
                    activity.setStartDate(activityDto.getStartDate());
                    activity.setEndDate(activityDto.getEndDate());
                    activity.setAddress(activityDto.getAddress());
                    activity.setLongitude(activityDto.getLongitude());
                    activity.setLatitude(activityDto.getLatitude());
                    activity.setPersonNum(activityDto.getPersonNum());
                    activity.setMinSpeed(activityDto.getMinSpeed());
                    activity.setMaxSpeed(activityDto.getMaxSpeed());
                    activity.setDistance(activityDto.getDistance());
                    activity.setExtraService(activityDto.getExtraService());
                    activity.setDetail(activityDto.getDetail());

                    activityMapper.updateByPrimaryKeySelective(activity);
                    return ResponseUtil.ok(activity.getId());
                })
                .orElseGet(ResponseUtil::badArgumentValue);
    }

    /**
     * 删除自己创建的活动
     * @param id 活动id
     */
    public Object delete(Long id) {
        Activity activity = new Activity();
        activity.setId(id);
        activity.setUserId(UserUtil.getUserId());
        activity.setStatus(ActivityStatusEnum.OBSOLETED);
        activityMapper.updateByPrimaryKeySelective(activity);
        return ResponseUtil.ok();
    }

    public Activity findById(Long activityId) {
        return activityMapper.wrapper()
                .eq(Activity::getId, activityId)
                .one()
                .orElse(null);
    }

    public int updateWithOptimisticLocker(Activity activity, ActivityStatusEnum status) {
        LocalDateTime preUpdateTime = activity.getUpdateTime();
        return activityMapper.updateWithOptimisticLocker(preUpdateTime, activity.getId(), status.getValue());
    }

    public List<Activity> getValidList() {
        List<ActivityStatusEnum> activityStatusList = Arrays.asList(ActivityStatusEnum.PENDING,
                ActivityStatusEnum.LOCKED, ActivityStatusEnum.PROGRESSING);
        return activityMapper.wrapper()
                .in(Activity::getStatus, activityStatusList)
                .list();
    }
}
